package ch.simas.nbtostring.options;

import ch.simas.nbtostring.ToStringGenerator;
import ch.simas.nbtostring.builder.ToStringBuilderType;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import org.openide.util.NbPreferences;

/**
 * A class used to obtain preferences for toString() generator.
 * @author cperv
 * @since 0.3.0
 */
public class ToStringPreferences{

    private static final ToStringPreferences INSTANCE = new ToStringPreferences();
    private final Preferences prefs;

    // key section to load/store preferences

    private final static String codeStyleKey = "CodeStyle";
    private final static String arrayStyleKey = "ArrayStyle";
    private final static String addOverideKey = "AddOverride";
    private final static String chainAppendsKey = "ChainAppends";
    private final static String showHideMethodsKey = "ShowHideMethods";

    private ToStringPreferences() {
        prefs = NbPreferences.forModule(ToStringGenerator.class);
    }

    /**
     * Gets the one and only instance of this.
     * @return the instance of this
     */
    public static final ToStringPreferences getDefault() {
        return INSTANCE;
    }

    /**
     * Gets the stored type for the code style. If none could be found {@link ToStringBuilderType#STRING} is returned
     * as default.
     * @return the type of code style
     */
    public ToStringBuilderType getBuilderType() {
        ToStringBuilderType ret = ToStringBuilderType.STRING;

        // we could use ToStringBuilderType.valueOf(String) here, but that throws an IllegalArgumentException we have
        // to catch then. That's a somewhat bad coding style
        for (ToStringBuilderType toStringBuilderType : ToStringBuilderType.values()) {
            if(toStringBuilderType.name().equals(prefs.get(codeStyleKey, null))) {
                ret = toStringBuilderType;
                break;
            }
        }
        return ret;
    }

    /**
     * Sets the type of code style to use.
     * @param toSet the style to use. If {@code null} is given, {@link ToStringBuilderType#STRING} will be stored
     */
    void setBuilderType(final ToStringBuilderType toSet) {
        prefs.put(codeStyleKey, toSet != null ? toSet.name() : ToStringBuilderType.STRING.name());
    }

    /**
     * Gets the style how to handle arrays.
     * @return {@code true} if to use Arrays.toString(), {@code false} for native toString()
     */
    public boolean getArrayStyle() {
        return prefs.getBoolean(arrayStyleKey, true);
    }

    void setArrayStyle(final boolean style) {
        prefs.putBoolean(arrayStyleKey, style);
    }

    /**
     * Indicates whether to automatically add {@code @Override} annotation.
     * @return {@code true} if to add the override annotation (default), {@code false} if not to do so
     */
    public boolean getOverride() {
        return prefs.getBoolean(addOverideKey, true);
    }

    /**
     * Sets whether to add the {@code @Override} annotation.
     * @param set {@code true} for setting the annotation automatically
     */
    void setOverride(final boolean set) {
        prefs.putBoolean(addOverideKey, set);

    }

    /**
     * Indicates whether to show or hide methods. Default is {@code true}
     * @return {@code true} if to show methods
     */
    public boolean isShowMethods() {
      return prefs.getBoolean(showHideMethodsKey, true);
    }

    /**
     * Sets whether to show ({@code true} or to hide methods
     * @param show {@code true} to show methods
     */
    void setShowMethods(final boolean show) {
      prefs.putBoolean(showHideMethodsKey, show);
    }

    /**
     * Indicates whether to chain append calls for StringBuilder/-Buffer usage.
     * @return {@code true} if to chain appends
     */
    public boolean isChainedAppend() {
      return prefs.getBoolean(chainAppendsKey, false);
    }

    /**
     * Sets the property to chain append() method calls
     * @param chained {@code true} if to enable appends
     */
    void setChainedAppends(final boolean chained) {
      prefs.putBoolean(chainAppendsKey, chained);
    }

    void store() {
        try {
            prefs.flush();
        } catch (BackingStoreException ex) {
            Logger.getLogger("ToString").info("Can not flush preferences!");
        }
    }

}
